<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
			body {
				font-size: 12px;
			}

			.company_content {
				border: 1px solid rgb(51, 136, 255);
			}
		</style>
	</head>
	<body>
		<!-- <button type="button" onclick="open()">展开/关闭</button> -->
		<svg id="s" width="19700" height="3700" style="overflow-x: scroll;" version="1.1" baseProfile="full"
			xmlns="http://www.w3.org/2000/svg" style="background: #fff">

			<defs>
				<marker fill="rgb(51, 136, 255)" id="arrowhead" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6"
					markerHeight="6" orient="auto">
					<path d="M 0 0 L 10 5 L 0 10 z" />
				</marker>
			</defs>
		</svg>

	</body>
</html>
<script src="data.js" type="text/javascript" charset="utf-8"></script>
<script src="data/data.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
	//公司之间的水平边距
	var levelSeparate = 40;
	//公司之间的垂直边距
	var verticalSeparate = 20;
	//公司宽度
	var companyWidth = 26;
	//公司高度
	var companyHeight = 180;
	var status = false;

	class Svg {
		constructor(el) {
			this.svg = document.getElementById("s");
		}

		append(element) {
			this.svg.appendChild(element.toElement())
		}
	}

	var SVG_NS = "http://www.w3.org/2000/svg";
	var svg = new Svg("s");

	class Polyline {
		constructor(startX, startY, endX, endY, company) {
			this.element = document.createElementNS(SVG_NS, "polyline")
			this.startX = startX;
			this.startY = startY;
			this.endX = endX;
			this.endY = endY;
			this.company = company;

			this.element.setAttribute("points", this._points(this.startX, this.startY, this.endX, this.endY))
			this.element.setAttribute("style", "fill:none;stroke:rgb(51, 136, 255);stroke-width:1");
			this.element.setAttribute("fill-opacity", "0")
			this.element.setAttribute("marker-end", "url(#arrowhead)")
		}

		_points(startX, startY, endX, endY) {
			let linePoint1 = startX + "," + startY;
			let linePoint2 = startX + "," + (startY + (verticalSeparate / 2));
			let linePoint3 = (endX + (this.company.getWidth() / 2)) + "," + (startY + (verticalSeparate / 2));
			let linePoint4 = (endX + (this.company.getWidth() / 2)) + "," + endY;
			return linePoint1 + " " + linePoint2 + " " + linePoint3 + " " + linePoint4;
		}

		updateX(x) {
			this.element.setAttribute("points", this._points(this.startX, this.startY, x, this.endY))
		}

		toElement() {
			return this.element;
		}
	}

	class Company {
		constructor(x, y, txt, w, h) {
			this.x = x;
			this.y = y;
			this.height = h != null ? h : companyHeight;
			this.width = w != null ? w : companyWidth;
			this.g = document.createElementNS(SVG_NS, "g")
			this.g.setAttribute("transform", "translate(" + x + "," + y + ")")
			this.g.appendChild(this._createHTML(txt))
			svg.append(this)
			this.polyline = null;
			this.children = [];
			this.childrenX = this.x;
		}

		getWidth() {
			return this.width;
		}

		_createRect() {
			let rect = document.createElementNS(SVG_NS, "rect");
			rect.setAttribute("width", companyWidth + "px")
			rect.setAttribute("height", companyHeight + "px")
			rect.setAttribute("fill", "#fff")
			rect.setAttribute("stroke-width", "1")
			rect.setAttribute("stroke", "rgb(0,0,0)");
			return rect;
		}

		_createHTML(txt) {
			let foreignObject = document.createElementNS(SVG_NS, "foreignObject")
			foreignObject.setAttribute("class", "htmlContent")
			foreignObject.setAttribute("width", this.width + "px")
			foreignObject.setAttribute("height", this.height + "px")

			let div = document.createElement("div")
			div.setAttribute("class", "company_content")
			div.setAttribute("style", "width:18px;margin:0 auto;height:" + (this.height - 2) +
				"px;1px solid rgb(51, 136, 255); overflow-y:auto;background:rgb(249, 252, 255);border-radius:3px;color:#333;text-align:center;"
			);
			div.innerHTML = "<span style='width:14px;writing-mode: vertical-rl;transform: rotate(360deg);'>" + txt+ "</span>"

			foreignObject.appendChild(div);
			return foreignObject;
		}

		getX() {
			return this.x;
		}

		getY() {
			return this.y;
		}

		_updatePosition(x, y) {
			this.g.setAttribute("transform", "translate(" + x + "," + y + ")")
			this.x = x;
			this.y = y;
		}

		/**
		 * 偏移
		 * @param {Object} len 偏移的像素值
		 */
		offset(targetX) {
			//移动当前元素位置，并改变连接线位置
			this._updatePosition(targetX, this.y);
			//改变连接线位置
			this.polyline.updateX(targetX + (this.width / 2))
		}

		_childrenStartX() {
			return this.x;
		}

		setPolyline(polyline) {
			this.polyline = polyline;
		}

		appendChild(company, w) {
			//挂载子元素
			let childrenWidth = w ? w : companyWidth;
			let x = this.childrenX;
			let y = this.y + companyHeight + verticalSeparate;
			let c = new Company(x,
				y,
				(company.name),
				childrenWidth,
				companyHeight
			);
			this.children.push(c)
			svg.append(c)

			//画连接线
			let lineX = this.x + (this.width / 2);
			let lineY = this.y + companyHeight;
			let polyline = new Polyline(lineX, lineY, x, y, c)
			svg.append(polyline)
			c.setPolyline(polyline)

			this.childrenX += w;
			return c;
		}

		toElement() {
			return this.g;
		}
	}





	//根节点
	var rootX = 1800,
		rootY = 40;

	//一个完整的公司所占有的宽度
	var companyFullWidth = companyWidth;

	//根节点
	// svg.append(new Company(rootX, rootY, "根节点"))

	function render(sx, sy, data_list) {
		//计算出第一个公司应该出现的位置
		let x = sx - ((data_list.length * companyFullWidth) / 2 - (companyWidth / 2));
		let y = sy + companyHeight + verticalSeparate;
		let lineX = sx + (companyWidth / 2);
		let lineY = sy + companyHeight;
		let childrenX, childrenY;

		for (var i = 0; i < data_list.length; i++) {
			let data = data_list[i]
			if (data.parent_name) {
				//画公司
				svg.append(new Company(x, y, data.name, companyWidth, companyHeight))
				//划连接线
				svg.append(new Polyline(lineX, lineY, x, y))
				//子集的起点
				childrenX = x;
				childrenY = y;
			} else {
				//画公司
				svg.append(new Company(sx, sy, data.name, companyWidth, companyHeight))
				//子集的起点
				childrenX = sx;
				childrenY = sy;
			}

			//画下级元素
			if (data.children) {
				render(childrenX, childrenY, data.children)
			}
			//向右偏移出一个公司的宽度，叠加的宽度设置为子级的数量*公司宽度
			x += (companyWidth)
		}
	}
	//render(rootX, rootY, company_list);

	class Tree {
		constructor(data, x, y) {
			this.data = data;
			this.childrens = [];
			this.x = x;
			this.y = y;
		}

		setX(x) {
			this.x = x;
		}

		setY(y) {
			this.y = y;
		}

		getName() {
			return this.data.name;
		}

		/**
		 * 添加子元素
		 * @param {Tree} children 子元素
		 */
		addChildren(children) {
			this.childrens.push(children);
		}

		getChildrens() {
			return this.childrens;
		}

		getWidth() {
			if (!this.childrens || this.childrens.length == 0) {
				return companyWidth;
			}

			let width = 0;
			for (var i = 0; i < this.childrens.length; i++) {
				let c = this.childrens[i];
				width += c.getWidth();
			}
			return width;
		}

	}

	

	function parseTree(tree, companys) {
		for (var i = 0; i < companys.length; i++) {
			let company = companys[i];
			let children = new Tree(company);
			tree.addChildren(children)
			if (company.children) {
				parseTree(children, company.children)
			}
		}
	}

	function renderTree(tree, x, y, parent) {
		if (!parent) {
			parent = new Company(x, y, tree.getName(), tree.getWidth())
		}
		for (var i = 0; i < tree.getChildrens().length; i++) {
			let ct = tree.getChildrens()[i]
			let c = parent.appendChild({
				name: ct.getName()
			}, ct.getWidth())
			if (ct.getChildrens().length > 0) {
				renderTree(ct, null, null, c)
			}
		}
	}
	function listToTree(arr) {
		let resArr = []
		arr.forEach(v => {
			// 找这个元素的 父亲(item.id === v.parentId)
			// 去arr中 中 找v的父亲，找到的话，把v添加到父亲的children属性中
			let parentNode = arr.find(item => item.name == v.parent_name);
			if (parentNode) {
				// 如果没有找到父亲-说明 他是一级目录
				if (parentNode['children']) {
					parentNode['children'].push(v);
				} else {
					parentNode['children'] = [v];
				}
			} else {
				//说明这个v 没有父亲
				// v 
				resArr.push(v)
			}
		});

		return resArr;
	}
	
	var x1 = 500,
		y1 = 500;
	var treeData = listToTree(data)[0];
	console.log("treeData",listToTree(data))
	
	var tree = new Tree(treeData);
	parseTree(tree, treeData.children);
	
	console.log(tree)
	renderTree(tree, 500, 500);
</script>
